package com.xyzh05.model;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.OneToMany;
import javax.persistence.OneToOne;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import javax.xml.bind.annotation.XmlRootElement;

import org.compass.annotations.Searchable;
import org.compass.annotations.SearchableId;
import org.compass.annotations.SearchableProperty;
import org.hibernate.annotations.Formula;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

import com.xyzh05.util.DateUtil;

@Entity
@Table(name="user")
@Searchable
@XmlRootElement
public class User extends BaseObject implements Serializable, UserDetails  {
	private static final long serialVersionUID = -5803243792045564751L;
	
	/** 正常状态 */
	public static final Short STATUS_NORMAL = 0;
	/** 锁定状态 */
	public static final Short STATUS_LOCKED = 1;
	/** 过期状态 */
	public static final Short STATUS_EXPIRED = 2;
	/** 无效状态 */
	public static final Short STATUS_DISABLED = 4;
	
	/**保密*/
	public static final Long GENDER_UNKNOWN = 0L;
	/** 男 */
	public static final Long GENDER_MALE = 1L;
	/** 女 */
	public static final Long GENDER_FEMALE = 2L;
	
	private Long id;
    private String username;
    private String password;
    private String email;
    private String name;
    private Long level = Role.ROLE_TYPE_USER;
    private String phone;
    private String nickname;
    private Date birthday;
    private String undergraduate;
    private Long major = 0L;
    private String avatar;
    private Long timezone = 0L;
    private String tomajor;
    private Long sex = GENDER_UNKNOWN;
    private String hometown;
    private String homecity;
    private Long previousip = 0L;
    private Long currentip = 0L;
    private Long registip = 0L;
    private Date registtime = DateUtil.getNow();
    private Date lastlogintime = DateUtil.getNow();
    private Date logintime = DateUtil.getNow();
    private Long school = 0L;
    private Long issubscribe = 0L;
    private Long survey = 0L;
    private Long dreamschool = 0L;
    private Long applyyear = 0L;
    private String lang = "zh_CN";
    private Short status = STATUS_NORMAL;
    private Boolean credentialsExpired = Boolean.FALSE;
    private UserInfo userInfo = new UserInfo();
    private Set<Role> roles = new HashSet<Role>(0);
    
    private String majorName; //专业
    private Long currentVip; //当前VIP任务数量
    private Long completevip; //已完成VIP数量
    private Long role;
    private List<VipServiceTransaction> vipServiceTransaction;

    @Id @GeneratedValue(strategy=GenerationType.AUTO) @SearchableId    
    public Long getId() {
        return this.id;
    }
    
    public void setId(Long id) {
        this.id = id;
    }
    @OneToMany( mappedBy = "user", fetch = FetchType.LAZY) 
    public List<VipServiceTransaction> getVipServiceTransaction() {
		return vipServiceTransaction;
	}

	public void setVipServiceTransaction(
			List<VipServiceTransaction> vipServiceTransaction) {
		this.vipServiceTransaction = vipServiceTransaction;
	}

	@Column(name="username", unique=true, nullable=false, length=128)
    @SearchableProperty
    public String getUsername() {
        return this.username;
    }
    
    public void setUsername(String username) {
        this.username = username;
    }
    
    @Column(name="password", nullable=false, length=64)
    @SearchableProperty
    public String getPassword() {
        return this.password;
    }
    
    public void setPassword(String password) {
        this.password = password;
    }
    
    @Column(name="email", unique=true, nullable=false, length=128)
    @SearchableProperty
    public String getEmail() {
        return this.email;
    }
    
    public void setEmail(String email) {
        this.email = email;
    }
    
    @Column(name="name", nullable=false, length=128)
    @SearchableProperty
    public String getName() {
        return this.name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    @Column(name="level", nullable=false)
    @SearchableProperty
    public Long getLevel() {
        return this.level;
    }
    
    public void setLevel(Long level) {
        this.level = level;
    }
    
    @Column(name="phone", length=32)
    @SearchableProperty
    public String getPhone() {
        return this.phone;
    }
    
    public void setPhone(String phone) {
        this.phone = phone;
    }
    
    @Column(name="nickname", length=128)
    @SearchableProperty
    public String getNickname() {
        return this.nickname;
    }
    
    public void setNickname(String nickname) {
        this.nickname = nickname;
    }
    
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name="birthday", nullable=false, length=19)
    @SearchableProperty
    public Date getBirthday() {
        return this.birthday;
    }
    
    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
    
    @Column(name="undergraduate")
    @SearchableProperty
    public String getUndergraduate() {
        return this.undergraduate;
    }
    
    public void setUndergraduate(String undergraduate) {
        this.undergraduate = undergraduate;
    }
    
    @Column(name="major", nullable=false)
    @SearchableProperty
    public Long getMajor() {
        return this.major;
    }
    
    public void setMajor(Long major) {
        this.major = major;
    }
    
    @Column(name="avatar")
    @SearchableProperty
    public String getAvatar() {
        return this.avatar;
    }
    
    public void setAvatar(String avatar) {
        this.avatar = avatar;
    }
    
    @Column(name="timezone")
    @SearchableProperty
    public Long getTimezone() {
        return this.timezone;
    }
    
    public void setTimezone(Long timezone) {
        this.timezone = timezone;
    }
    
    @Column(name="tomajor")
    @SearchableProperty
    public String getTomajor() {
        return this.tomajor;
    }
    
    public void setTomajor(String tomajor) {
        this.tomajor = tomajor;
    }
    
    @Column(name="sex")
    @SearchableProperty
    public Long getSex() {
        return this.sex;
    }
    
    public void setSex(Long sex) {
        this.sex = sex;
    }
    
    @Column(name="hometown")
    @SearchableProperty
    public String getHometown() {
        return this.hometown;
    }
    
    public void setHometown(String hometown) {
        this.hometown = hometown;
    }
    
    @Column(name="homecity")
    @SearchableProperty
    public String getHomecity() {
        return this.homecity;
    }
    
    public void setHomecity(String homecity) {
        this.homecity = homecity;
    }
    
    @Column(name="previousip")
    @SearchableProperty
    public Long getPreviousip() {
        return this.previousip;
    }
    
    public void setPreviousip(Long previousip) {
        this.previousip = previousip;
    }
    
    @Column(name="currentip")
    @SearchableProperty
    public Long getCurrentip() {
        return this.currentip;
    }
    
    public void setCurrentip(Long currentip) {
        this.currentip = currentip;
    }
    
    @Column(name="registip")
    @SearchableProperty
    public Long getRegistip() {
        return this.registip;
    }
    
    public void setRegistip(Long registip) {
        this.registip = registip;
    }
    
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name="registtime", nullable=false, length=19)
    @SearchableProperty
    public Date getRegisttime() {
        return this.registtime;
    }
    
    public void setRegisttime(Date registtime) {
        this.registtime = registtime;
    }
    
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name="lastlogintime", nullable=false, length=19)
    @SearchableProperty
    public Date getLastlogintime() {
        return this.lastlogintime;
    }
    
    public void setLastlogintime(Date lastlogintime) {
        this.lastlogintime = lastlogintime;
    }
    
    @Temporal(TemporalType.TIMESTAMP)
    @Column(name="logintime", nullable=false, length=19)
    @SearchableProperty
    public Date getLogintime() {
        return this.logintime;
    }
    
    public void setLogintime(Date logintime) {
        this.logintime = logintime;
    }
    
    @Column(name="school", nullable=false)
    @SearchableProperty
    public Long getSchool() {
        return this.school;
    }
    
    public void setSchool(Long school) {
        this.school = school;
    }
    
    @Column(name="issubscribe", nullable=false)
    @SearchableProperty
    public Long getIssubscribe() {
        return this.issubscribe;
    }
    
    public void setIssubscribe(Long issubscribe) {
        this.issubscribe = issubscribe;
    }
    
    @Column(name="survey", nullable=false)
    @SearchableProperty
    public Long getSurvey() {
        return this.survey;
    }
    
    public void setSurvey(Long survey) {
        this.survey = survey;
    }
    
    @Column(name="dreamschool", nullable=false)
    @SearchableProperty
    public Long getDreamschool() {
        return this.dreamschool;
    }
    
    public void setDreamschool(Long dreamschool) {
        this.dreamschool = dreamschool;
    }
    
    @Column(name="applyyear", nullable=false)
    @SearchableProperty
    public Long getApplyyear() {
        return this.applyyear;
    }
    
    public void setApplyyear(Long applyyear) {
        this.applyyear = applyyear;
    }
    
    @Column(name="lang", length=8)
    @SearchableProperty
    public String getLang() {
        return this.lang;
    }
    
    public void setLang(String lang) {
        this.lang = lang;
    }
    
    @OneToOne(cascade=CascadeType.ALL, fetch=FetchType.LAZY, mappedBy="user")
    public UserInfo getUserInfo() {
		return userInfo;
	}

	public void setUserInfo(UserInfo userInfo) {
		this.userInfo = userInfo;
	}
	
	@ManyToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY)
    @JoinTable(name="user_role", joinColumns = { 
    @JoinColumn(name="user_id", nullable=false, updatable=false) }, inverseJoinColumns = { 
    @JoinColumn(name="role_id", nullable=false, updatable=false) })
    public Set<Role> getRoles() {
        return this.roles;
    }
    
    public void setRoles(Set<Role> roles) {
        this.roles = roles;
    }
    
    @Column(name="status", nullable=false)
    @SearchableProperty
    public Short getStatus() {
        return this.status;
    }
    
    public void setStatus(Short status) {
        this.status = status;
    }
    
    @Column(name = "credentials_expired", nullable = false)
	public Boolean isCredentialsExpired() {
		return credentialsExpired;
	}

	public void setCredentialsExpired(Boolean credentialsExpired) {
		this.credentialsExpired = credentialsExpired;
	}
	
	@Formula("(select ur.role_id from user_role ur where ur.user_id = id)")
	public Long getRole() {
		return role;
	}

	public void setRole(Long role) {
		this.role = role;
	}

	@Transient
    public Boolean isAdminRole(){
    	return Role.ROLE_TYPE_ADMIN == getMainRole().getId();
    }
    
	@Transient
    public Boolean isAdviserRole(){
    	return Role.ROLE_TYPE_ADVISER == getMainRole().getId();
    }
    
	@Transient
    public Boolean isEditorInChiefRole(){
    	return Role.ROLE_TYPE_EDITOR_IN_CHIEF == getMainRole().getId();
    }
    
	@Transient
    public Boolean isEditorRole(){
    	return Role.ROLE_TYPE_EDITOR == getMainRole().getId();
    }
    
	@Transient
    public Boolean isUserRole(){
    	return Role.ROLE_TYPE_USER == getMainRole().getId();
    }
    
	
	/**
     * 获得用户角色
     * @return
     */
    @Transient
    public Role getMainRole(){
    	Role role = null;
    	for (Role r : roles) {
    		role = r;
    		break;
    	}
    	return role;
    }
    
    /**
     * Convert user roles to LabelValue objects for convenience.
     *
     * @return a list of LabelValue objects with role information
     */
    @Transient
    public List<LabelValue> getRoleList() {
        List<LabelValue> userRoles = new ArrayList<LabelValue>();

        if (this.roles != null) {
            for (Role role : roles) {
                // convert the user's roles to LabelValue Objects
                userRoles.add(new LabelValue(role.getName(), role.getName()));
            }
        }

        return userRoles;
    }

    /**
     * Adds a role for the user
     *
     * @param role the fully instantiated role
     */
    public void addRole(Role role) {
        getRoles().add(role);
    }
    
    /**
     * @return GrantedAuthority[] an array of roles.
     * @see org.springframework.security.core.userdetails.UserDetails#getAuthorities()
     */
    @Transient
    public Set<GrantedAuthority> getAuthorities() {
        Set<GrantedAuthority> authorities = new LinkedHashSet<GrantedAuthority>();
        authorities.addAll(roles);
        return authorities;
    }

	private boolean checkBit(Short checker) {
		return (status.shortValue() & checker.shortValue()) > 0;
	}
	
	/**
     * @see org.springframework.security.core.userdetails.UserDetails#isAccountNonExpired()
     * @return true if account is still active
     */
    @Transient
	public boolean isAccountNonExpired() {
		return !checkBit(STATUS_EXPIRED);
	}

    /**
     * @see org.springframework.security.core.userdetails.UserDetails#isAccountNonLocked()
     * @return false if account is locked
     */
    @Transient
	public boolean isAccountNonLocked() {
		return !checkBit(STATUS_LOCKED);
	}

    /**
     * @see org.springframework.security.core.userdetails.UserDetails#isCredentialsNonExpired()
     * @return true if credentials haven't expired
     */
    @Transient
	public boolean isCredentialsNonExpired() {
		return !isCredentialsExpired();
	}

    /**
     * @see org.springframework.security.core.userdetails.UserDetails#isCredentialsNonExpired()
     * @return true if credentials haven't expired
     */
    @Transient
	public boolean isEnabled() {
		return !checkBit(STATUS_DISABLED);
	}       
    
    @Formula("(select m.name from Major m where m.id=major)")
    public String getMajorName() {
		return majorName;
	}

	public void setMajorName(String majorName) {
		this.majorName = majorName;
	}

	@Transient
	public Long getCurrentVip() {
		return currentVip;
	}

	public void setCurrentVip(Long currentVip) {
		this.currentVip = currentVip;
	}

	@Transient
	public Long getCompletevip() {
		return completevip;
	}

	public void setCompletevip(Long completevip) {
		this.completevip = completevip;
	}

	public User(){    	
    }
    
    public User(Long id, String username,String nickname){
    	this.id = id;
    	this.username = username;
    	this.nickname = nickname;
    }
    public User(Long id, String nickname, String majorName, Long currentVip, Long completevip, Date registtime){
    	this.id = id;
    	this.nickname = nickname;
    	this.majorName = majorName;
    	this.currentVip = currentVip;
    	this.completevip = completevip;
    	this.registtime = registtime;    	
    }
    
    public User(Long id, String nickname, String majorName, Date registtime){
    	this.id = id;
    	this.nickname = nickname;
    	this.majorName = majorName;
    	this.registtime = registtime;
    }
    
    public User(Long id, String nickname, String majorName, Date registtime, Long role){
    	this.id = id;
    	this.nickname = nickname;
    	this.majorName = majorName;
    	this.registtime = registtime;
    	this.role = role;
    }
    
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        User pojo = (User) o;

        if (username != null ? !username.equals(pojo.username) : pojo.username != null) return false;
        if (password != null ? !password.equals(pojo.password) : pojo.password != null) return false;
        if (email != null ? !email.equals(pojo.email) : pojo.email != null) return false;
        if (name != null ? !name.equals(pojo.name) : pojo.name != null) return false;
        if (level != null ? !level.equals(pojo.level) : pojo.level != null) return false;
        if (phone != null ? !phone.equals(pojo.phone) : pojo.phone != null) return false;
        if (nickname != null ? !nickname.equals(pojo.nickname) : pojo.nickname != null) return false;
        if (birthday != null ? !birthday.equals(pojo.birthday) : pojo.birthday != null) return false;
        if (undergraduate != null ? !undergraduate.equals(pojo.undergraduate) : pojo.undergraduate != null) return false;
        if (major != null ? !major.equals(pojo.major) : pojo.major != null) return false;
        if (avatar != null ? !avatar.equals(pojo.avatar) : pojo.avatar != null) return false;
        if (timezone != null ? !timezone.equals(pojo.timezone) : pojo.timezone != null) return false;
        if (tomajor != null ? !tomajor.equals(pojo.tomajor) : pojo.tomajor != null) return false;
        if (sex != null ? !sex.equals(pojo.sex) : pojo.sex != null) return false;
        if (hometown != null ? !hometown.equals(pojo.hometown) : pojo.hometown != null) return false;
        if (homecity != null ? !homecity.equals(pojo.homecity) : pojo.homecity != null) return false;
        if (previousip != null ? !previousip.equals(pojo.previousip) : pojo.previousip != null) return false;
        if (currentip != null ? !currentip.equals(pojo.currentip) : pojo.currentip != null) return false;
        if (registip != null ? !registip.equals(pojo.registip) : pojo.registip != null) return false;
        if (registtime != null ? !registtime.equals(pojo.registtime) : pojo.registtime != null) return false;
        if (lastlogintime != null ? !lastlogintime.equals(pojo.lastlogintime) : pojo.lastlogintime != null) return false;
        if (logintime != null ? !logintime.equals(pojo.logintime) : pojo.logintime != null) return false;
        if (school != null ? !school.equals(pojo.school) : pojo.school != null) return false;
        if (issubscribe != null ? !issubscribe.equals(pojo.issubscribe) : pojo.issubscribe != null) return false;
        if (survey != null ? !survey.equals(pojo.survey) : pojo.survey != null) return false;
        if (dreamschool != null ? !dreamschool.equals(pojo.dreamschool) : pojo.dreamschool != null) return false;
        if (applyyear != null ? !applyyear.equals(pojo.applyyear) : pojo.applyyear != null) return false;
        if (lang != null ? !lang.equals(pojo.lang) : pojo.lang != null) return false;
        if (status != null ? !status.equals(pojo.status) : pojo.status != null) return false;
        if (credentialsExpired != null ? !credentialsExpired.equals(pojo.credentialsExpired) : pojo.credentialsExpired != null) return false;

        return true;
    }

    public int hashCode() {
        int result = 0;
        result = (username != null ? username.hashCode() : 0);
        result = 31 * result + (password != null ? password.hashCode() : 0);
        result = 31 * result + (email != null ? email.hashCode() : 0);
        result = 31 * result + (name != null ? name.hashCode() : 0);
        result = 31 * result + (level != null ? level.hashCode() : 0);
        result = 31 * result + (phone != null ? phone.hashCode() : 0);
        result = 31 * result + (nickname != null ? nickname.hashCode() : 0);
        result = 31 * result + (birthday != null ? birthday.hashCode() : 0);
        result = 31 * result + (undergraduate != null ? undergraduate.hashCode() : 0);
        result = 31 * result + (major != null ? major.hashCode() : 0);
        result = 31 * result + (avatar != null ? avatar.hashCode() : 0);
        result = 31 * result + (timezone != null ? timezone.hashCode() : 0);
        result = 31 * result + (tomajor != null ? tomajor.hashCode() : 0);
        result = 31 * result + (sex != null ? sex.hashCode() : 0);
        result = 31 * result + (hometown != null ? hometown.hashCode() : 0);
        result = 31 * result + (homecity != null ? homecity.hashCode() : 0);
        result = 31 * result + (previousip != null ? previousip.hashCode() : 0);
        result = 31 * result + (currentip != null ? currentip.hashCode() : 0);
        result = 31 * result + (registip != null ? registip.hashCode() : 0);
        result = 31 * result + (registtime != null ? registtime.hashCode() : 0);
        result = 31 * result + (lastlogintime != null ? lastlogintime.hashCode() : 0);
        result = 31 * result + (logintime != null ? logintime.hashCode() : 0);
        result = 31 * result + (school != null ? school.hashCode() : 0);
        result = 31 * result + (issubscribe != null ? issubscribe.hashCode() : 0);
        result = 31 * result + (survey != null ? survey.hashCode() : 0);
        result = 31 * result + (dreamschool != null ? dreamschool.hashCode() : 0);
        result = 31 * result + (applyyear != null ? applyyear.hashCode() : 0);
        result = 31 * result + (lang != null ? lang.hashCode() : 0);
        result = 31 * result + (status != null ? status.hashCode() : 0);
        result = 31 * result + (credentialsExpired != null ? credentialsExpired.hashCode() : 0);

        return result;
    }

    public String toString() {
        StringBuffer sb = new StringBuffer(getClass().getSimpleName());

        sb.append(" [");
        sb.append("id").append("='").append(getId()).append("', ");
        sb.append("username").append("='").append(getUsername()).append("', ");
        sb.append("password").append("='").append(getPassword()).append("', ");
        sb.append("email").append("='").append(getEmail()).append("', ");
        sb.append("name").append("='").append(getName()).append("', ");
        sb.append("level").append("='").append(getLevel()).append("', ");
        sb.append("phone").append("='").append(getPhone()).append("', ");
        sb.append("nickname").append("='").append(getNickname()).append("', ");
        sb.append("birthday").append("='").append(getBirthday()).append("', ");
        sb.append("undergraduate").append("='").append(getUndergraduate()).append("', ");
        sb.append("major").append("='").append(getMajor()).append("', ");
        sb.append("avatar").append("='").append(getAvatar()).append("', ");
        sb.append("timezone").append("='").append(getTimezone()).append("', ");
        sb.append("tomajor").append("='").append(getTomajor()).append("', ");
        sb.append("sex").append("='").append(getSex()).append("', ");
        sb.append("hometown").append("='").append(getHometown()).append("', ");
        sb.append("homecity").append("='").append(getHomecity()).append("', ");
        sb.append("previousip").append("='").append(getPreviousip()).append("', ");
        sb.append("currentip").append("='").append(getCurrentip()).append("', ");
        sb.append("registip").append("='").append(getRegistip()).append("', ");
        sb.append("registtime").append("='").append(getRegisttime()).append("', ");
        sb.append("lastlogintime").append("='").append(getLastlogintime()).append("', ");
        sb.append("logintime").append("='").append(getLogintime()).append("', ");
        sb.append("school").append("='").append(getSchool()).append("', ");
        sb.append("issubscribe").append("='").append(getIssubscribe()).append("', ");
        sb.append("survey").append("='").append(getSurvey()).append("', ");
        sb.append("dreamschool").append("='").append(getDreamschool()).append("', ");
        sb.append("applyyear").append("='").append(getApplyyear()).append("', ");
        sb.append("lang").append("='").append(getLang()).append("', ");
        sb.append("status").append("='").append(getStatus()).append("', ");
        sb.append("credentialsExpired").append("='").append(isCredentialsExpired()).append("', ");
        sb.append("]");
      
        return sb.toString();
    }

}
